home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dvips / dospecial.c < prev    next >
C/C++ Source or Header  |  1990-01-27  |  12KB  |  424 lines

  1. /*
  2.  *   This routine handles special commands;
  3.  *   predospecial() is for the prescan, dospecial() for the real thing.
  4.  */
  5. #include "structures.h" /* The copyright notice in that file is included too! */
  6. #ifdef SYSV
  7. #include <string.h>
  8. #else
  9. #include <strings.h>
  10. #endif
  11.  
  12. /*
  13.  *   These are the external routines called:
  14.  */
  15. /**/
  16. #ifdef TPIC
  17. extern void setPenSize();
  18. extern void flushPath();
  19. extern void flushDashed();
  20. extern void flushDashed();
  21. extern void addPath();
  22. extern void arc();
  23. extern void flushSpline();
  24. extern void shadeLast();
  25. extern void whitenLast();
  26. extern void blackenLast();
  27. #endif
  28. extern shalfword dvibyte() ;
  29. extern void add_header() ;
  30. extern void hvpos() ;
  31. extern void figcopyfile() ;
  32. extern char *malloc() ;
  33. extern void cmdout() ;
  34. extern void numout() ;
  35. extern void scout() ;
  36. extern void stringend() ;
  37. extern void error() ;
  38. extern char errbuf[] ;
  39. extern shalfword linepos;
  40. extern Boolean usesspecial ;
  41. extern char *paperfmt ;
  42. extern char *nextstring;
  43. extern char *maxstring;
  44. extern char *oname;
  45. extern FILE *bitfile;
  46. extern int quiet;
  47. extern fontdesctype *curfnt ;
  48. extern int actualdpi ;
  49. extern real conv ;
  50. #ifdef DEBUG
  51. extern integer debug_flag;
  52. #endif
  53.  
  54. struct bangspecial {
  55.    struct bangspecial *next ;
  56.    char actualstuff[1] ; /* more space will actually be allocated */
  57. } *bangspecials = NULL ;
  58.  
  59. static trytobreakout(p)
  60. register char *p ;
  61. {
  62.    register int i ;
  63.    register int instring = 0 ;
  64.    int lastc = 0 ;
  65.  
  66.    i = 0 ;
  67.    while (*p) {
  68.       if (i > 65 && *p == ' ' && instring == 0) {
  69.          (void)putc('\n', bitfile) ;
  70.          i = 0 ;
  71.       } else {
  72.          (void)putc(*p, bitfile) ;
  73.          i++ ;
  74.       }
  75.       if (*p == '(' && lastc != '\\')
  76.          instring = 1 ;
  77.       else if (*p == ')' && lastc != '\\')
  78.          instring = 0 ;
  79.       lastc = *p ;
  80.       p++ ;
  81.    }
  82. }
  83.  
  84. static dobs(q)
  85. register struct bangspecial *q ;
  86. {
  87.    if (q) {
  88.       dobs(q->next) ;
  89.       trytobreakout(q->actualstuff) ;
  90.    }
  91. }
  92.  
  93. void
  94. outbangspecials() {
  95.    if (bangspecials) {
  96.       cmdout("TeXDict") ;
  97.       cmdout("begin") ;
  98.       cmdout("@defspecial\n") ;
  99.       dobs(bangspecials) ;
  100.       cmdout("\n@fedspecial") ;
  101.       cmdout("end") ;
  102.    }
  103. }
  104.  
  105. /* We recommend that new specials be handled by the following general
  106.  * (and extensible) scheme, in which the user specifies one or more
  107.  * `key=value' pairs separated by spaces.
  108.  * The known keys are given in KeyTab; they take values
  109.  * of one of the following types:
  110.  *
  111.  * None: no value, just a keyword (in which case the = sign is omitted)
  112.  * String: the value should be "<string without double-quotes"
  113.  *                          or '<string without single-quotes'
  114.  * Integer: the value should be a decimal integer (%d format)
  115.  * Number: the value should be a decimal integer or real (%f format)
  116.  * Dimension: like Number, but will be multiplied by the scaledsize
  117.  *       of the current font and converted to default PostScript units
  118.  * (Actually, strings are allowed in all cases; the delimiting quotes
  119.  *  are simply stripped off if present.)
  120.  *
  121.  */
  122.  
  123. typedef enum {None, String, Integer, Number, Dimension} ValTyp;
  124. typedef struct {
  125.    char    *Entry;
  126.    ValTyp  Type;
  127. } KeyDesc;
  128.  
  129. #define NKEYS    (sizeof(KeyTab)/sizeof(KeyTab[0]))
  130.  
  131. KeyDesc KeyTab[] = {{"psfile",  String}, /* j==0 in the routine below */
  132.                     {"ifffile", String}, /* j==1 */
  133.                     {"tekfile", String}, /* j==2 */
  134.                     {"hsize",   Number},
  135.                     {"vsize",   Number},
  136.                     {"hoffset", Number},
  137.                     {"voffset", Number},
  138.                     {"hscale",  Number},
  139.                     {"vscale",  Number},
  140.                     {"angle",   Number},
  141.                     {"llx", Number},
  142.                     {"lly", Number},
  143.                     {"urx", Number},
  144.                     {"ury", Number},
  145.                     {"rwi", Number}};
  146.  
  147. /*
  148.  * compare strings, ignore case
  149.  */
  150. char Tolower(c)
  151. register char c ;
  152. {
  153.    if ('A' <= c && c <= 'Z')
  154.       return(c+32) ;
  155.    else
  156.       return(c) ;
  157. }
  158. int IsSame(a, b)
  159. char *a, *b;
  160. {
  161.    for( ; *a != '\0'; )
  162.       if( Tolower(*a++) != Tolower(*b++) ) 
  163.          return( 0 );
  164.       return( *b == '\0' );
  165. }
  166.  
  167. char KeyStr[STRINGSIZE], ValStr[STRINGSIZE] ; /* Key and String values found */
  168. long ValInt ; /* Integer value found */
  169. float ValNum ; /* Number or Dimension value found */
  170.  
  171. char  *GetKeyVal(str,tno) /* returns NULL if none found, else next scan point */
  172.    char *str ; /* starting point for scan */
  173.    int  *tno ; /* table entry number of keyword, or -1 if keyword not found */
  174. {
  175.    register char *s, *k ;
  176.    register int i ;
  177.    register char t ;
  178.    char c = '\0' ;
  179.  
  180.    for (s=str; *s <= ' ' && *s; s++) ; /* skip over blanks */
  181.    if (*s == '\0')
  182.       return (NULL) ;
  183.    for (k=KeyStr; *s>' ' && *s!='='; *k++ = *s++) ; /* copy the keyword */
  184.    *k = '\0' ;
  185.  
  186.    for(i=0; i<NKEYS; i++)
  187.       if( IsSame(KeyStr, KeyTab[i].Entry) )
  188.          goto found ;
  189.    *tno = -1;
  190.    return (s) ;
  191.  
  192. found: *tno = i ;
  193.    ValStr[0] = '\0' ;
  194.    if (KeyTab[i].Type == None)
  195.       return (s) ;
  196.  
  197.    for (; *s <= ' ' && *s; s++) ; /* now look for the value part */
  198.    if ( *s == '=' ) {
  199.       for (s++; *s <= ' ' && *s; s++) ;
  200.       if (*s=='\'' || *s=='\"')
  201.          t = *s++ ;               /* get string delimiter */
  202.       else t = ' ' ;
  203.       for (k=ValStr; *s!=t && *s; *k++ = *s++) ; /* copy the value portion */
  204.       if (*s == t )
  205.             s++ ;                    /* advance past matching delimiter */
  206.       *k = '\0' ;
  207.    }
  208.    switch (KeyTab[i].Type) {
  209.  case Integer:
  210.       if(sscanf(ValStr,"%ld%c",&ValInt,&c)!=1 || c!='\0') {
  211.           sprintf(errbuf,"Non-integer value (%s) given for keyword %s",
  212.               ValStr, KeyStr) ;
  213.           error(errbuf) ;
  214.           ValInt = 0 ;
  215.       }
  216.       break ;
  217.  case Number:
  218.  case Dimension:
  219.       if(sscanf(ValStr,"%f%c",&ValNum,&c)!=1 || c!='\0') {  
  220.           sprintf(errbuf,"Non-numeric value (%s) given for keyword %s",
  221.               ValStr, KeyStr) ;
  222.           error(errbuf) ;
  223.           ValNum = 0 ;
  224.       }
  225.       if (KeyTab[i].Type==Dimension) {
  226.          if (curfnt==NULL)
  227.             error("! No font selected") ;
  228.          ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI ;
  229.       }
  230.       break ;
  231.  default: break ;
  232.    }
  233.    return (s) ;
  234. }
  235.  
  236. /*
  237.  *   Now our routines.  We get the number of bytes specified and place them
  238.  *   into the string buffer, and then parse it. Numerous conventions are
  239.  *   supported here for historical reasons.
  240.  */
  241.  
  242. void predospecial(numbytes)
  243. integer numbytes ;
  244. {
  245.    register char *p = nextstring ;
  246.    register int i = 0 ;
  247.  
  248.    if (nextstring + i > maxstring)
  249.       error("! out of string space in predospecial") ;
  250.    for (i=numbytes; i>0; i--)
  251.       *p++ = (char)dvibyte() ;
  252.    while (p[-1] <= ' ' && p > nextstring)
  253.       p-- ; /* trim trailing blanks */
  254.    if (p==nextstring) return ; /* all blank is no-op */
  255.    *p = 0 ;
  256.    p = nextstring ;
  257.    while (*p <= ' ')
  258.       p++ ;
  259. #ifdef DEBUG
  260.    if (dd(D_SPECIAL))
  261.       (void)fprintf(stderr, "Preprocessing special: %s\n", p) ;
  262. #endif
  263.  
  264.    if (strcmp(p, "landscape")==0) {
  265.       paperfmt = "landscape" ;
  266.       return ;
  267.    }
  268.    usesspecial = 1 ;  /* now the special prolog will be sent */
  269.    if (strncmp(p, "header", 6)==0) {
  270.       char *q ;
  271.       p += 6 ;
  272.       while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
  273.          p++ ;
  274.       q = p ;  /* we will remove enclosing parentheses */
  275.       p = p + strlen(p) - 1 ;
  276.       while ((*p <= ' ' || *p == ')') && p >= q)
  277.          p-- ;
  278.       p[1] = 0 ;
  279.       if (p >= q)
  280.          add_header(q) ;
  281.    }
  282.    else if (*p == '!') {
  283.       register struct bangspecial *q ;
  284.       p++ ;
  285.       q = (struct bangspecial *)malloc((unsigned)
  286.                          (sizeof(struct bangspecial) + strlen(p))) ;
  287.       if (q == NULL)
  288.          error("! out of memory in predospecial") ;
  289.       (void)strcpy(q->actualstuff, p) ;
  290.       q->next = bangspecials ;
  291.       bangspecials = q ;
  292.    }
  293. }
  294.  
  295. void dospecial(numbytes)
  296. integer numbytes ;
  297. {
  298.    register char *p = nextstring ;
  299.    register int i = 0 ;
  300.    int j ;
  301.    char psfile[100] ; 
  302.    char cmdbuf[100] ; 
  303.    register char *q ;
  304.    Boolean psfilewanted = 1 ;
  305.  
  306.    if (nextstring + i > maxstring)
  307.       error("! out of string space in dospecial") ;
  308.    for (i=numbytes; i>0; i--)
  309.       *p++ = (char)dvibyte() ;
  310.    while (p[-1] <= ' ' && p > nextstring)
  311.       p-- ; /* trim trailing blanks */
  312.    if (p==nextstring) return ; /* all blank is no-op */
  313.    *p = 0 ;
  314.    p = nextstring ;
  315.    while (*p <= ' ')
  316.       p++ ;
  317. #ifdef DEBUG
  318.    if (dd(D_SPECIAL))
  319.       (void)fprintf(stderr, "Processing special: %s\n", p) ;
  320. #endif
  321.  
  322.    if (strncmp(p, "ps:", 3)==0) {
  323.         hvpos() ;
  324.         if (p[3]==':') {
  325.            if (strncmp(p+4, "[begin]", 7) == 0)
  326.               cmdout(&p[11]);
  327.            else if (strncmp(p+4, "[end]", 5) == 0)
  328.               cmdout(&p[9]);
  329.            else cmdout(&p[4]);
  330.         } else if (strncmp(p+3, " plotfile ", 10) == 0) {
  331.            char *sfp ;
  332.            p += 13;
  333.            for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
  334.            *sfp = '\0';
  335.            figcopyfile (p);
  336.         } else
  337.            cmdout(&p[3]);
  338.         return;
  339.    }
  340.    if (strcmp(p, "landscape")==0 || strncmp(p, "header", 6)==0 || *p=='!')
  341.       return ; /* already handled in prescan */
  342. #ifdef TPIC
  343.    if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
  344.    if (strcmp(p, "fp") == 0) {flushPath(); return;}
  345.    if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
  346.    if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
  347.    if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
  348.    if (strncmp(p, "ar ", 3) == 0) {arc(p+2); return;}
  349.    if (strcmp(p, "sp") == 0) {flushSpline(); return;}
  350.    if (strcmp(p, "sh") == 0) {shadeLast(); return;}
  351.    if (strcmp(p, "wh") == 0) {whitenLast(); return;}
  352.    if (strcmp(p, "bk") == 0) {blackenLast(); return;}
  353.    if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
  354. #endif
  355.    if (*p == '"') {
  356.       hvpos();
  357.       cmdout("@beginspecial") ;
  358.       cmdout("@setspecial\n") ;
  359.       trytobreakout(p+1) ;
  360.       cmdout("\n@endspecial") ;
  361.       return ;
  362.    }
  363.  
  364. /* At last we get to the key/value conventions */
  365.    psfile[0] = '\0';
  366.    hvpos();
  367.    cmdout("@beginspecial");
  368.  
  369.    while( (p=GetKeyVal(p,&j)) != NULL )
  370.       switch (j) {
  371.  case -1: /* for compatability with old conventions, we allow a file name
  372.            * to be given without the 'psfile=' keyword */
  373.          if (!psfile[0] && access(KeyStr,4)==0) /* yes we can read it */
  374.              (void)strcpy(psfile,KeyStr) ;
  375.          else {
  376.            sprintf(errbuf, "Unknown keyword (%s) in \\special will be ignored",
  377.                               KeyStr) ;
  378.            error(errbuf) ;
  379.          }
  380.          break ;
  381.  case 0: /* psfile */
  382.          if (psfile[0]) {
  383.            sprintf(errbuf, "More than one \\special psfile given; %s ignored", 
  384.                               ValStr) ;
  385.            error(errbuf) ;
  386.          }
  387.          else (void)strcpy(psfile,ValStr) ;
  388.          break ;
  389.  case 1: case 2:
  390.          sprintf(errbuf, 
  391.             "Sorry, there's presently no \\special support for %s", KeyStr) ;
  392.          error(errbuf) ;
  393.          psfilewanted = 0 ;
  394.          break ;
  395.  default: /* most keywords are output as PostScript procedure calls */
  396.          if (KeyTab[j].Type == Integer)
  397.             numout(ValInt);
  398.          else if (KeyTab[j].Type == String)
  399.             for (q=ValStr; *q; q++)
  400.                scout(*q) ;
  401.          else if (KeyTab[j].Type == None) ;
  402.          else { /* Number or Dimension */
  403.             ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5) ;
  404.             if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
  405.                 numout(ValInt) ;
  406.             else {
  407.                (void)sprintf(cmdbuf, "%f", ValNum) ;
  408.                cmdout(cmdbuf) ;
  409.             }
  410.          }
  411.       (void)sprintf(cmdbuf, "@%s", KeyStr);
  412.       cmdout(cmdbuf) ;
  413.       }
  414.  
  415.    cmdout("@setspecial");
  416.  
  417.    if(psfile[0]) {
  418.       figcopyfile(psfile);
  419.    } else if (psfilewanted)
  420.       error("No \\special psfile was given; figure will be blank") ;
  421.  
  422.    cmdout("@endspecial");
  423. }
  424.